feat(differentials): interactive diagnosis detail page with honest safety snapshot#483
Conversation
…clipboard util - src/lib/differential-detail.ts: pure client-safe helpers (item cleaning, tone-aware visible items, honest safety facts, copy text, presentation grouping, tab ids) with vitest coverage - getDifferentialDetailContext in src/lib/differentials.ts: server-side catalog lookups (validated related slugs, overlap title links, compare presentation mapping, snapshot governance) passed as a small prop so the client never bundles the snapshot JSON - shared copyTextToClipboard with legacy fallback, adopted by the service detail page and CopyAfterReviewButton - saved-registry storage key for locally saved differentials Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Section rows become controlled native <details> disclosures revealing the previously unrendered section items, with tone-specific bodies (numbered immediate actions, danger-tinted must-not-miss list, linked mimic chips), cleaned count badges, empty-section static fallback, and expand/collapse all - Safety snapshot: status-aware theming (danger/warning/neutral instead of always red), honest facts (curated for delirium, derived counts elsewhere), "Watch for" chip relabel, and a review-must-not-miss CTA that opens and scrolls to the section - Dead controls wired: Copy after review (real clipboard + Copied feedback), Compare buttons switch to the compare tab, bookmark persists locally with aria-pressed, header "+" starts a new differentials search; dead overflow button removed - Compare tab reworked into an honest panel linking related diagnoses and the matching comparison workspace; Related rows become links with notes; Current presentation renders hinge callouts; Source tab shows real snapshot governance (live values when hydrated) - Tabs gain roving-tabindex arrow-key navigation and ?tab= deep links via history.replaceState; map panel "Open diagnosis" now routes to the selected related node Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… Next-reserved dev ports - New ui-tools describe block: disclosure toggling with items, expand all, safety CTA scroll-open, honest facts on non-curated records, keyboard tab navigation and ?tab= deep links, compare/related/source content, copy feedback, bookmark persistence, tap targets, and 320-1440px overflow guards - Port scanners skip Chrome/Next reserved ports (e.g. 4045) so worktrees whose path-derived stable port lands on one can still boot dev and Playwright servers Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rst-load waits - Safety snapshot chips run through cleanDifferentialItem so export artifacts like trailing full stops do not render - Detail-page e2e navigations share a 30s first-assertion helper (the route is not in the runner warm-up smoke set, so the first hit of a run can pay the dev-server compile) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…page-review-a3daaf # Conflicts: # scripts/dev-free-port.mjs # scripts/local-server-utils.mjs # scripts/run-playwright.mjs # src/components/differentials/differential-detail-page.tsx
…server-utils The origin/main merge relocated local-server-utils.mjs to src/lib/; the reserved-port additions were applied to the working tree during conflict resolution but missed the index, leaving the committed scripts importing a missing isReservedDevPort export. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…page-review-a3daaf
|
This pull request has been ignored for the connected project Preview Branches by Supabase. |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThe pull request adds an interactive differential diagnosis detail page with server-provided context, saved state, accessible tabs, related-diagnosis navigation, and expanded tests. It also centralizes clipboard fallback behavior and excludes reserved development ports. ChangesDifferential diagnosis detail flow
Shared clipboard handling
Development port reservation
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant Browser
participant DiagnosisRoute
participant DetailContext
participant DifferentialDetailPage
participant LocalStorage
Browser->>DiagnosisRoute: Request diagnosis route
DiagnosisRoute->>DetailContext: Build detailContext for record
DiagnosisRoute->>DifferentialDetailPage: Render record and context
DifferentialDetailPage->>LocalStorage: Read and write saved diagnosis state
Browser->>DifferentialDetailPage: Change tab, expand section, copy, or compare
DifferentialDetailPage-->>Browser: Render context-aware detail view
🚥 Pre-merge checks | ✅ 10 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (10 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
✨ Simplify code
Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7c94fae052
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (5)
scripts/run-playwright.mjs (1)
71-77: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winConsider consolidating duplicated
findFreePortlogic.
findFreePorthere is nearly identical to the one inscripts/dev-free-port.mjs(differing only in the loop bound:projectPortEndvsmaxPort). Now that both shareisReservedDevPort/stableProjectPortfromlocal-server-utils.mjs, extracting a sharedfindFreePort(startPort, endPort)helper into that module would remove the remaining duplication and prevent future drift (e.g., if the reserved-port skip logic needs to change again).♻️ Suggested shared helper (illustrative)
// src/lib/local-server-utils.mjs export async function findFreePort(startPort, endPort, canListen) { for (let port = startPort; port <= endPort; port += 1) { if (isReservedDevPort(port)) continue; if (await canListen(port)) return port; } throw new Error(`No free port found from ${startPort} to ${endPort}.`); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@scripts/run-playwright.mjs` around lines 71 - 77, Consolidate the duplicated findFreePort logic from scripts/run-playwright.mjs and scripts/dev-free-port.mjs into a shared findFreePort(startPort, endPort, canListen) helper in local-server-utils.mjs. Preserve reserved-port skipping and inclusive bounds, update both callers to pass their respective end ports and canListen functions, and retain clear no-free-port error handling.src/lib/differential-detail.ts (1)
138-157: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winInvestigations list is unbounded in the clipboard register, unlike actions.
actionsis capped toslice(0, 6)(Line 145) butinvestigations(Lines 150-154) has no cap. A record with many investigations produces an unbounded "Copy after review" clipboard payload, inconsistent with the actions cap.💡 Proposed fix
- const investigations = record.investigations.map(cleanDifferentialItem).filter(Boolean); + const investigations = record.investigations.map(cleanDifferentialItem).filter(Boolean).slice(0, 6);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/lib/differential-detail.ts` around lines 138 - 157, Cap the investigations included by formatDifferentialCopyText to the same six-item limit as immediate actions. Update the investigations mapping/filtering chain to apply slice(0, 6) before rendering the “Investigations” section.src/lib/differentials.ts (1)
124-159: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winRedundant snapshot load and uncached catalog Set inside
getDifferentialDetailContext.Two inefficiencies compound in this function, called once per diagnosis page render/build:
- Line 125 rebuilds
catalogSlugsas a freshSeton every call, unlike the memoizeddiagnosisTitleSlugMap()pattern used just above it.- Line 140 calls
differentialPresentations()(which internally loads the snapshot viacatalog()), then Line 144 callsloadDifferentialSnapshot()again directly — reloading/reparsing the same snapshot twice per call. Sincecatalog()is literallyreturn loadDifferentialSnapshot();, this second call is redundant and can reuse the same snapshot object.Across many statically generated diagnosis pages (
generateStaticParams), this adds up to unnecessary repeated I/O/parsing during build.♻️ Proposed fix
const presentation = - differentialPresentations().find((workflow) => + catalog().presentations.find((workflow) => workflow.candidates.some((candidate) => candidate.slug === record.slug), ) ?? null; - const snapshot = loadDifferentialSnapshot(); + const snapshot = catalog(); const governance = deriveGovernanceFromSnapshot(snapshot);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/lib/differentials.ts` around lines 124 - 159, Optimize getDifferentialDetailContext by reusing memoized data: introduce a module-level or memoized catalog slug Set instead of rebuilding catalogSlugs on every call, and load the differential snapshot once before deriving presentation and governance. Reuse that snapshot for differentialPresentations or add an equivalent snapshot-aware path so the function does not trigger the catalog-backed load and then call loadDifferentialSnapshot again.src/components/differentials/differential-detail-page.tsx (2)
447-501: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDuplicated related-node row markup between
RelatedDiagnosesandComparePanel.Both components repeat the same title/note + likelihood-badge + conditional
Link-vs-divwrapper structure (lines 456-497 and 598-630) with only cosmetic class differences. Extracting a small sharedRelatedNodeRowhelper (takingnode,known, and avariantfor styling) would remove ~50 lines of near-identical JSX and keep future tone/badge changes in one place.Also applies to: 597-631
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/differentials/differential-detail-page.tsx` around lines 447 - 501, Extract the duplicated related-node row JSX from RelatedDiagnoses and ComparePanel into a shared RelatedNodeRow helper that accepts the node, known-state, and styling variant. Preserve the existing title, note, likelihood badge, conditional Link-versus-div behavior, test id, href, and cosmetic class differences, then replace both inline implementations with the helper.
812-844: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win
aria-controlson inactive tabs points to an unmounted panel id.Every tab button sets
aria-controls={differential-panel-${tab.id}}, but only one<div role="tabpanel" id={differential-panel-${activeTab}}>is ever rendered (line 1002). For the four inactive tabs,aria-controlsreferences an id that doesn't exist in the DOM, which is a real ARIA authoring-practices violation for tabs (each tab'saria-controlsshould resolve to an existing panel element).🔧 Proposed fix
- aria-controls={`differential-panel-${tab.id}`} + aria-controls={isActive ? `differential-panel-${tab.id}` : undefined}Also applies to: 853-865
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/differentials/differential-detail-page.tsx` around lines 812 - 844, Fix the tab/panel ARIA relationship in the Tabs component and its tab button rendering: ensure every tab’s aria-controls references an existing panel element, either by rendering panels for all tabs or by removing aria-controls from inactive tabs and retaining it only for the active tab. Keep the panel IDs consistent with the tab IDs and update related aria attributes as needed.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/components/differentials/differential-diagnosis-page-client.tsx`:
- Around line 17-25: Recompute detailContext from the rendered resolvedRecord
instead of retaining the SSR snapshot context. Update the differential diagnosis
page component and its supporting helper or type definitions as needed so
overlap, related, compare, and source panels derive their context from
resolvedRecord for both fallback and fetched records.
In `@src/lib/copy-to-clipboard.ts`:
- Around line 22-27: Ensure the fallback copy path throws when
document.execCommand is unavailable or rejects the copy. In the try block of the
clipboard helper, explicitly verify that execCommand is a function before
invoking it, and throw an appropriate error when it is missing or returns false,
so callers such as CopyAfterReviewButton can detect failure.
---
Nitpick comments:
In `@scripts/run-playwright.mjs`:
- Around line 71-77: Consolidate the duplicated findFreePort logic from
scripts/run-playwright.mjs and scripts/dev-free-port.mjs into a shared
findFreePort(startPort, endPort, canListen) helper in local-server-utils.mjs.
Preserve reserved-port skipping and inclusive bounds, update both callers to
pass their respective end ports and canListen functions, and retain clear
no-free-port error handling.
In `@src/components/differentials/differential-detail-page.tsx`:
- Around line 447-501: Extract the duplicated related-node row JSX from
RelatedDiagnoses and ComparePanel into a shared RelatedNodeRow helper that
accepts the node, known-state, and styling variant. Preserve the existing title,
note, likelihood badge, conditional Link-versus-div behavior, test id, href, and
cosmetic class differences, then replace both inline implementations with the
helper.
- Around line 812-844: Fix the tab/panel ARIA relationship in the Tabs component
and its tab button rendering: ensure every tab’s aria-controls references an
existing panel element, either by rendering panels for all tabs or by removing
aria-controls from inactive tabs and retaining it only for the active tab. Keep
the panel IDs consistent with the tab IDs and update related aria attributes as
needed.
In `@src/lib/differential-detail.ts`:
- Around line 138-157: Cap the investigations included by
formatDifferentialCopyText to the same six-item limit as immediate actions.
Update the investigations mapping/filtering chain to apply slice(0, 6) before
rendering the “Investigations” section.
In `@src/lib/differentials.ts`:
- Around line 124-159: Optimize getDifferentialDetailContext by reusing memoized
data: introduce a module-level or memoized catalog slug Set instead of
rebuilding catalogSlugs on every call, and load the differential snapshot once
before deriving presentation and governance. Reuse that snapshot for
differentialPresentations or add an equivalent snapshot-aware path so the
function does not trigger the catalog-backed load and then call
loadDifferentialSnapshot again.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 7a87c7bc-76e1-41f7-b829-43905fa57067
📒 Files selected for processing (15)
scripts/dev-free-port.mjsscripts/run-playwright.mjssrc/app/differentials/diagnoses/[slug]/page.tsxsrc/components/differentials/diagnosis-map-panel.tsxsrc/components/differentials/differential-detail-page.tsxsrc/components/differentials/differential-diagnosis-page-client.tsxsrc/components/differentials/differential-presentation-actions.tsxsrc/components/services/service-detail-page.tsxsrc/lib/copy-to-clipboard.tssrc/lib/differential-detail.tssrc/lib/differentials.tssrc/lib/local-server-utils.mjssrc/lib/saved-registry-storage.tstests/differential-detail.test.tstests/ui-tools.spec.ts
document.execCommand?.("copy") returns undefined when the API is absent, so
the helper resolved successfully and CopyAfterReviewButton reported "Copied"
without copying. Only an explicit true now counts as success; unit tests
cover the clipboard path, the fallback, and both failure modes.
Addresses the Codex P2 and CodeRabbit findings on PR #483.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 947e836adb
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…page-review-a3daaf
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 53faf4801a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…ave on mobile - /api/differentials/[slug] now returns a server-computed detailContext for every diagnosis payload (snapshot and owner-row branches), and the client prefers it once hydrated so link validation, compare target, and source info always match the record being rendered; SSR context stays as fallback - The mobile action strip gains the bookmark toggle (TopActions is lg-only, so small viewports previously had no save control); covered by the mobile e2e - Route test asserts the demo-mode payload carries the delirium context Addresses the Codex P2 review findings on PR #483. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 36cca1bf7c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 40342dab08
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 061c888026
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
# Conflicts: # docs/branch-review-ledger.md
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0c32a24b64
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/lib/differentials.ts (1)
121-152: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick winHonor the catalog override in routability checks
catalog.records/catalog.presentationsare used for lookup, butknownRelatedSlugs,overlapLinks, andcomparePresentationstill gate against the module-level catalog only. In the owner-row API path that passesownerRecords/ownerPresentations, any owner-specific related diagnosis or presentation not present in the bundled snapshot is dropped from the detail context.Use the override entries when building the routable slug/id sets, or the
catalogparameter only works for title matching and not for link generation.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/lib/differentials.ts` around lines 121 - 152, The routability sets in getDifferentialDetailContext currently use the module-level differentialRecords and differentialPresentations instead of the resolved catalogRecords and catalogPresentations. Build routableDiagnosisSlugs and routablePresentationSlugs from the catalog override values so knownRelatedSlugs, overlapLinks, and presentation/comparePresentation retain owner-specific entries.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@src/lib/differentials.ts`:
- Around line 121-152: The routability sets in getDifferentialDetailContext
currently use the module-level differentialRecords and differentialPresentations
instead of the resolved catalogRecords and catalogPresentations. Build
routableDiagnosisSlugs and routablePresentationSlugs from the catalog override
values so knownRelatedSlugs, overlapLinks, and presentation/comparePresentation
retain owner-specific entries.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 0cf95da8-8ff8-4bbe-b7e0-b892be43aeb1
📒 Files selected for processing (5)
docs/branch-review-ledger.mdsrc/lib/differentials.tstests/differentials-route.test.tstests/ui-smoke.spec.tstests/ui-tools.spec.ts
✅ Files skipped from review due to trivial changes (2)
- docs/branch-review-ledger.md
- tests/ui-smoke.spec.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- tests/differentials-route.test.ts
- tests/ui-tools.spec.ts
…n taps Rebuilt on top of #483's redesigned interactive detail page (which already fixed the wrapping action labels and tab-label wrap). Remaining polish: - Add a .focus-ring-tab class (inset rounded ring: outline-offset -4px, no halo) so keyboard focus no longer draws a full-height box that collides with the tablist border; inactive tabs get a transparent bottom border to remove the 2px layout jump on tab switch. - Keep #483's roving-tabindex keyboard nav, nowrap and flex-1 layout intact. - shrink-0 on the desktop action cluster so the Save icon button stops being crushed below 44px at ~1024px; nowrap on the Compare button. - Bump the two overlap-diagnosis chips to the 44px tap standard. - Regression test: detail Save action >=44px at 1024px, Overview tab single-line with no page overflow at 320px. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…n taps Rebuilt on top of #483's redesigned interactive detail page (which already fixed the wrapping action labels and tab-label wrap). Remaining polish: - Add a .focus-ring-tab class (inset rounded ring: outline-offset -4px, no halo) so keyboard focus no longer draws a full-height box that collides with the tablist border; inactive tabs get a transparent bottom border to remove the 2px layout jump on tab switch. - Keep #483's roving-tabindex keyboard nav, nowrap and flex-1 layout intact. - shrink-0 on the desktop action cluster so the Save icon button stops being crushed below 44px at ~1024px; nowrap on the Compare button. - Bump the two overlap-diagnosis chips to the 44px tap standard. - Regression test: detail Save action >=44px at 1024px, Overview tab single-line with no page overflow at 320px. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(differentials): shape the detail tab focus ring and firm up action taps Rebuilt on top of #483's redesigned interactive detail page (which already fixed the wrapping action labels and tab-label wrap). Remaining polish: - Add a .focus-ring-tab class (inset rounded ring: outline-offset -4px, no halo) so keyboard focus no longer draws a full-height box that collides with the tablist border; inactive tabs get a transparent bottom border to remove the 2px layout jump on tab switch. - Keep #483's roving-tabindex keyboard nav, nowrap and flex-1 layout intact. - shrink-0 on the desktop action cluster so the Save icon button stops being crushed below 44px at ~1024px; nowrap on the Compare button. - Bump the two overlap-diagnosis chips to the 44px tap standard. - Regression test: detail Save action >=44px at 1024px, Overview tab single-line with no page overflow at 320px. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(ui): click-ring artifact and sub-44px tap targets across production routes Still-present defects confirmed by a fresh sweep of current main (15 routes x 7 widths); none were addressed by recent main changes: - DocumentTagCloud: drop the focus: ring classes that painted a ring on mouse click; the global :focus-visible rule keeps the keyboard ring. - applications launcher category filters: mobile 28px / desktop 36px -> 44px, with whitespace-nowrap. - service detail Copy row buttons: 40px -> 44px. - favourites command-library More-actions buttons and library sidebar rows and compact toggle: 36px -> 44px. Deliberately left main's intentional lg:min-h-9 desktop density on the mode-home quick-link pills (AA-compliant for pointer). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(medication): use per-prompt action descriptions on the prescribing home The MedicationHome actions hardcoded description: "Prescribing-focused search." for every prompt, ignoring the authored `medicationPrompts[].description` values ("Check renal dosing…", "Review opioid-use…", "Check maximum dose…") that the prescribing-home responsive test asserts. Restore `description: prompt.description` so each card shows its specific guidance and the advisory UI regression passes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * 📝 Add docstrings to `claude/site-formatting-polish-b91374` (#503) --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Summary
/differentials/diagnoses/[slug]were static mockup rows with decorative chevrons; each section'sitems[]existed in the snapshot but was never rendered. They are now controlled native<details>disclosures with tone-specific bodies (numbered immediate actions sourced from the full record array, danger-tinted must-not-miss list, core-test checklist, mimic chips that link to real diagnosis pages), cleaned count badges that match the expanded content, a static fallback for the 454/1206 sections with no items, and an Expand all / Collapse all control.copyTextToClipboardutil with legacy fallback, "Copied" feedback), bookmark persisted locally (aria-pressed, survives reload), Compare buttons switch to the Compare tab, header "+" starts a new differentials search; the dead overflow button is removed.?tab=deep links viahistory.replaceState(route stays statically generated — nouseSearchParams).getDifferentialDetailContext): validated related slugs, overlap-title links, compare-presentation mapping, and governance travel as a small serializable prop so the client never bundles the 27.7k-line snapshot JSON.next devrefuses — dev and Playwright servers could not boot at all), ported onto the relocatedsrc/lib/local-server-utils.mjs; adopted fix(differentials): restore visible Safety Snapshot alert tint #468's full-opacity soft-token fix across the new status themes and all other-soft/NNwashes on this page.Verification
npm run verify:pr-local— constituents run individually on the merged HEAD:check:runtime✓,format:check✓ on every file this PR touches (the repo-wide sweep locally also flagsCLAUDE.md+.claude/settings.json, pre-existing CRLF working-copy artifacts untouched by this PR and green in CI on main),lint✓,typecheck✓,test✓ (1,492 passed / 1 skipped),build✓ (compiled successfully)npm run verify:ui— full Chromium suite on the merged HEAD from a pristine dev server: everything passes except two tests that fail identically on pureorigin/main(verified at detachedf1d350cc2with a fresh.next):ui-smoke › newer routed differential context wins over an older response(search fires 2× on load) andui-tools › all mode home heroes share identical sizing on mobile(hero heading 25.2px vs 25.6px contract). Both are untagged, so they run only in CI's advisory lane, not the requiredui-criticalgate; both are pre-existing upstream regressions flagged for separate fixes. All six new differential detail-page tests pass.npm run verify:release— not run (not a release/handoff claim)npm run eval:retrieval:quality— N/A: no retrieval, ranking, selection, chunking, or scoring behavior changed (differentials.tsgained a read-only catalog-context helper; rankers untouched)npm run eval:rag -- --limit 15— N/A: no answer generation, synthesis prompt, or answer post-processing changesnpm run check:production-readiness— N/A: no clinical workflow, privacy, environment, Supabase, source-governance, or deployment behavior changednpm run check:deployment-readiness— N/A: no deployment startup/hosting/rollout changesClinical Governance Preflight
Clinical KB Database(sjrfecxgysukkwxsowpy) — no env/config changeNotes
origin/maininto the branch (no rebase); resolved conflicts in the two port scripts (upstream relocatedlocal-server-utils.mjstosrc/lib/— reserved-port skip ported to the new location) and in the Safety Snapshot (kept the new status-themed structure while adopting fix(differentials): restore visible Safety Snapshot alert tint #468's full-opacity soft-token intent everywhere on the page).🤖 Generated with Claude Code